﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WordNet.Core.ElementContracts;

namespace WordNet.Core
{
    public sealed class ContentType<T>: IContentType<T>
    {

        public static readonly ContentType<IIndexWord> INDEX_NOUN = new ContentType<IIndexWord>(DataType<T>.INDEX, POS.GetPartOfSpeech(DbPartOfSpeechType.Noun), "index.noun");
        public static readonly ContentType<IIndexWord> INDEX_VERB = new ContentType<IIndexWord>(DataType<T>.INDEX, POS.GetPartOfSpeech(DbPartOfSpeechType.Verb), "index.verb");
        public static readonly ContentType<IIndexWord> INDEX_ADVERB = new ContentType<IIndexWord>(DataType<T>.INDEX, POS.GetPartOfSpeech(DbPartOfSpeechType.Adv), "index.adv");
        public static readonly ContentType<IIndexWord> INDEX_ADJECTIVE = new ContentType<IIndexWord>(DataType<T>.INDEX, POS.GetPartOfSpeech(DbPartOfSpeechType.Adj), "index.adj");

        public static readonly ContentType<ISynset> DATA_NOUN = new ContentType<ISynset>(DataType<T>.DATA, POS.GetPartOfSpeech(DbPartOfSpeechType.Noun),  "data.noun");
        public static readonly ContentType<ISynset> DATA_VERB = new ContentType<ISynset>(DataType<T>.DATA, POS.GetPartOfSpeech(DbPartOfSpeechType.Verb), "data.verb");
        public static readonly ContentType<ISynset> DATA_ADVERB = new ContentType<ISynset>(DataType<T>.DATA, POS.GetPartOfSpeech(DbPartOfSpeechType.Adv), "data.adv");
        public static readonly ContentType<ISynset> DATA_ADJECTIVE = new ContentType<ISynset>(DataType<T>.DATA, POS.GetPartOfSpeech(DbPartOfSpeechType.Adj), "data.adj");

        public static readonly ContentType<IExceptionEntryProxy> EXCEPTION_NOUN = new ContentType<IExceptionEntryProxy>(DataType<T>.EXCEPTION, POS.GetPartOfSpeech(DbPartOfSpeechType.Noun), "noun.exc");
        public static readonly ContentType<IExceptionEntryProxy> EXCEPTION_VERB = new ContentType<IExceptionEntryProxy>(DataType<T>.EXCEPTION, POS.GetPartOfSpeech(DbPartOfSpeechType.Verb), "verb.exc");
        public static readonly ContentType<IExceptionEntryProxy> EXCEPTION_ADVERB = new ContentType<IExceptionEntryProxy>(DataType<T>.EXCEPTION, POS.GetPartOfSpeech(DbPartOfSpeechType.Adv), "adv.exc");
        public static readonly ContentType<IExceptionEntryProxy> EXCEPTION_ADJECTIVE = new ContentType<IExceptionEntryProxy>(DataType<T>.EXCEPTION, POS.GetPartOfSpeech(DbPartOfSpeechType.Adj), "adj.exc");

        public static readonly ContentType<ISenseEntry> SENSE = new ContentType<ISenseEntry>(DataType<T>.SENSE, null, "index.sense");
        
        static ContentType()
        {
            LoadConfiguration();
        }

        private static void LoadConfiguration()
        {
            FieldInfo[] fields = typeof(ContentType<T>).GetFields(BindingFlags.Static | BindingFlags.Public);
           for (int i = 0; i < fields.Length; i++)
            {
                if (fields[i].FieldType == typeof(ContentType<T>))
                    _values.Add((ContentType<T>)fields[i].GetValue(null));
            }
        }
       
        private static readonly HashSet<IContentType<T>> _values = new HashSet<IContentType<T>>();
        private readonly IDataType<T> _dataType;
        private readonly POS _pos;
        private readonly String _description;
        private readonly String _fileName;

        /// <summary>
        /// Constructs new ContentType
        /// </summary>
        /// <param name="type"></param>
        /// <param name="pos"></param>
        private ContentType(IDataType<T> type, POS pos, String fileName)
        {
            if (type == null || string.IsNullOrEmpty(fileName))
                throw new ArgumentNullException();
            _dataType = type;
            _pos = pos;
            _fileName = fileName;

            if (_pos != null)
               _description = String.Format("[ContentType: {0}/{1}", _dataType.ToString(),  _pos.Name);
            else
                _description = String.Format("[ContentType: {0}", _dataType.ToString());
        }

        public string FileName 
        { 
            get { return _fileName; } 
        }
        
        public IDataType<T> DataType
        {
           get { return _dataType; }
        }

        public POS PartOfSpeech
        {
            get { return _pos; }
        }

        public override string ToString()
        {
            return _description;
        }
        
        public static ICollection<IContentType<T>> Values { get { return _values; } }

        public static IContentType<IIndexWord> GetIndexContentType(POS pos)
        {
            switch (pos.Name)
            {
                case "noun":
                    return INDEX_NOUN;
                case "verb":
                    return INDEX_VERB;
                case "adverb":
                    return INDEX_ADVERB;
                case "adjective":
                    return INDEX_ADJECTIVE;
                default:
                    throw new ArgumentException();
            }
        }

        public static IContentType<ISynset> GetDataContentType(POS pos)
        {

            switch (pos.Name)
            {
                case "noun":
                    return DATA_NOUN;
                case "verb":
                    return DATA_VERB;
                case "adverb":
                    return DATA_ADVERB;
                case "adjective":
                    return DATA_ADJECTIVE;
                default:
                    throw new ArgumentException();
            }
        }

        public static IContentType<IExceptionEntryProxy> GetExceptionContentType(POS pos)
        {

            switch (pos.Name)
            {
                case "noun":
                    return EXCEPTION_NOUN;
                case "verb":
                    return EXCEPTION_VERB;
                case "adverb":
                    return EXCEPTION_ADVERB;
                case "adjective":
                    return EXCEPTION_ADJECTIVE;
                default:
                    throw new ArgumentException();
            }
        }
    }
}
